/*
 * GraphicsInstance.cpp
 *
 *  Created on: Jul 6, 2009
 *      Author: kurt
 */

#include "GraphicsInstance.h"

#include <pspgu.h>
#include <pspgum.h>
#include <valloc.h>
using namespace std;
using namespace objdraw;

//Line size in array of screen pixels on psp
#define PSP_LINE_SIZE 512
#define SCREEN_HEIGHT 272
#define SCREEN_WIDTH 480
#define FRAMEBUFFER_SIZE (PSP_LINE_SIZE*SCREEN_HEIGHT*4)
static unsigned int __attribute__((aligned(16))) display_list[262144];

GraphicsInstance::~GraphicsInstance() 
{
	_instance = NULL;
	sceGuTerm();
}
GraphicsInstance::GraphicsInstance() 
{
	
}
GraphicsInstance* GraphicsInstance::_instance = 0;// initialize pointer

GraphicsInstance* GraphicsInstance::Instance() 
{
   if (_instance == 0)
      _instance = new GraphicsInstance; // create sole instance
   return _instance; // address of sole instance
}
bool GraphicsInstance::Init3DGraphics() 
{
	//Initializes the GU, preparing it for use.
	
	sceGuInit(); //Turn on the GU
	
	sceGuStart(GU_DIRECT, display_list); //Start filling a command list.
	
//	Set memory locations
	
	displayBuffer = valloc(FRAMEBUFFER_SIZE);
	drawBuffer = valloc(FRAMEBUFFER_SIZE);
	depthBuffer = valloc(FRAMEBUFFER_SIZE);
	sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT,(void *) vGuPointer(displayBuffer), PSP_LINE_SIZE);
	sceGuDrawBuffer(GU_PSM_8888, (void *)vGuPointer(drawBuffer), PSP_LINE_SIZE);
	sceGuDepthBuffer((void*) vGuPointer(depthBuffer), PSP_LINE_SIZE);
	
//	Configure viewport
	
	sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2)); //Define current drawing area.
	
	sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT); //Center screen in virtual space.
	
//	Set up scissor test
	
	sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); //Sets up a scissor rect for the screen.
	
	sceGuEnable(GU_SCISSOR_TEST); //Enables scissor mode: pixels outside the scissor rect are not rendered.
	
//	Set up alpha test
	
	sceGuAlphaFunc(GU_GREATER, 0, 0xff); //if((alpha & 0xFF) > (0 & 0xFF)) {render pixel}
	
	sceGuEnable(GU_ALPHA_TEST); //Enables sceGuAlphaFunc
	
//	Set up depth test
	
	sceGuDepthRange(0xc350, 0x2710); //Tells the GU what value range to use within the depth buffer.
	
	sceGuDepthFunc(GU_GEQUAL); //Pixels with z less than or equal to the existing pixel z pass the test.
	
	sceGuEnable(GU_DEPTH_TEST); //Only pixels that pass sceGuDepthFunc are rendered.
	
//	Set up texture processing
	
	sceGuEnable(GU_TEXTURE_2D); //Enables texturing of primitives.
	
	sceGuTexMode(GU_PSM_8888, 0, 0, GU_FALSE); //32-bit colors, no mipmaps, (unk - set to 0), interpret images as swizzled
	
	sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); //Configure the formulas used when blitting an image using sceGuTexImage
	
	sceGuShadeModel(GU_SMOOTH); //Set shading model (required by dialogs)
	
//	Set up alpha blending
	
	sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //Set up blending formulas.
	
	sceGuEnable(GU_BLEND); //Activates blending according to sceGuBlendFunc
	
//	Set up screen clearing parameters
	
//	sceGuClearColor(0xFFFFFFFF); //Set the color used by sceGuClear when its passed GU_COLOR_BUFFER_BIT
	sceGuClearColor(0); //clear the screen black =)
	sceGuClearDepth(0); //Set the value to reset the depth buffer pixels to when using sceGuClear with the GU_DEPTH_BUFFER_BIT
	
//	Miscellanaus Stuff
	sceGuFrontFace(GU_CW);
	sceGuEnable(GU_CULL_FACE);
	sceGuEnable(GU_CLIP_PLANES);
	sceGuDisable(GU_TEXTURE_2D);
	sceGumOrtho(0,480,272,0,-1,1);
	
	sceGuFinish(); //End of command list
	
	sceGuSync(0, 0); //Wait for list to finish executing
	
	sceGuDisplay(GU_TRUE); //vram should be displayed on screen.
//	set so that we keep track of display of which display buffer is used
	dispBufferNumber = 0;
	return false;
}
unsigned int * GraphicsInstance::getDisplayList()
{
	return display_list;
}
unsigned int GraphicsInstance::getDisplayListSize()
{
	return sizeof(display_list);
}
void * GraphicsInstance::flipScreen()
{
	dispBufferNumber = !dispBufferNumber;
	return sceGuSwapBuffers();
}
void * GraphicsInstance::getVramDrawBuffer()
{
	return (void *)(dispBufferNumber ? displayBuffer : drawBuffer);
}
void * GraphicsInstance::getVramDisplayBuffer()
{
	return (void *)(dispBufferNumber ? drawBuffer : displayBuffer);
}
